From 6eda19e5e481f601c5d9b70d0c278672293208a9 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 5 Jun 2005 10:53:57 +0000 Subject: [PATCH] bitkeeper revision 1.1675 (42a2d9c5PelbdNceuL1qXullGOrtHA) ns16550 interrupt handler should not return until the IIR indicates no pending interrupts. Also a few generic serial driver cleanups. Signed-off-by: Keir Fraser --- xen/drivers/char/ns16550.c | 17 +++++++--- xen/drivers/char/serial.c | 65 ++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index f52ea04ac2..680a6ef1bc 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -49,7 +49,15 @@ static struct ns16550 { #define IER_ELSI 0x04 /* rx line status */ #define IER_EMSI 0x08 /* MODEM status */ -/* FIFO control register */ +/* Interrupt Identification Register */ +#define IIR_NOINT 0x01 /* no interrupt pending */ +#define IIR_IMASK 0x06 /* interrupt identity: */ +#define IIR_LSI 0x06 /* - rx line status */ +#define IIR_RDAI 0x04 /* - rx data recv'd */ +#define IIR_THREI 0x02 /* - tx reg. empty */ +#define IIR_MSI 0x00 /* - MODEM status */ + +/* FIFO Control Register */ #define FCR_ENABLE 0x01 /* enable FIFO */ #define FCR_CLRX 0x02 /* clear Rx FIFO */ #define FCR_CLTX 0x04 /* clear Tx FIFO */ @@ -59,7 +67,7 @@ static struct ns16550 { #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ -/* Line control register */ +/* Line Control Register */ #define LCR_DLAB 0x80 /* Divisor Latch Access */ /* Modem Control Register */ @@ -104,10 +112,11 @@ static void ns16550_interrupt( struct serial_port *port = dev_id; struct ns16550 *uart = port->uart; - if ( (ns_read_reg(uart, IIR) & 7) == 2 ) + while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) ) + { serial_tx_interrupt(port, regs); - else serial_rx_interrupt(port, regs); + } } static int ns16550_tx_empty(struct serial_port *port) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 2116d8ef08..51cfaa56eb 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -22,20 +22,13 @@ static struct serial_port com[2] = { void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) { char c; - serial_rx_fn fn; + serial_rx_fn fn = NULL; unsigned long flags; - BUG_ON(!port->driver); - BUG_ON(!port->driver->getc); + spin_lock_irqsave(&port->lock, flags); - for ( ; ; ) + if ( port->driver->getc(port, &c) ) { - spin_lock_irqsave(&port->lock, flags); - - if ( !port->driver->getc(port, &c) ) - break; - - fn = NULL; if ( port->rx != NULL ) fn = port->rx; else if ( (c & 0x80) && (port->rx_hi != NULL) ) @@ -44,16 +37,12 @@ void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) fn = port->rx_lo; else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ ) port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c; - - spin_unlock_irqrestore(&port->lock, flags); - - if ( fn != NULL ) - (*fn)(c & 0x7f, regs); - - cpu_relax(); } spin_unlock_irqrestore(&port->lock, flags); + + if ( fn != NULL ) + (*fn)(c & 0x7f, regs); } void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) @@ -61,18 +50,17 @@ void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) int i; unsigned long flags; - BUG_ON(!port->driver); - BUG_ON(!port->driver->tx_empty); - BUG_ON(!port->driver->putc); - spin_lock_irqsave(&port->lock, flags); - for ( i = 0; i < port->tx_fifo_size; i++ ) + if ( port->driver->tx_empty(port) ) { - if ( port->txbufc == port->txbufp ) - break; - port->driver->putc( - port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]); + for ( i = 0; i < port->tx_fifo_size; i++ ) + { + if ( port->txbufc == port->txbufp ) + break; + port->driver->putc( + port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]); + } } spin_unlock_irqrestore(&port->lock, flags); @@ -146,8 +134,29 @@ void serial_putc(int handle, char c) void serial_puts(int handle, const char *s) { - while ( *s != '\0' ) - serial_putc(handle, *s++); + struct serial_port *port = &com[handle & SERHND_IDX]; + unsigned long flags; + char c; + + if ( (handle == -1) || !port->driver || !port->driver->putc ) + return; + + spin_lock_irqsave(&port->lock, flags); + + while ( (c = *s++) != '\0' ) + { + if ( (c == '\n') && (handle & SERHND_COOKED) ) + __serial_putc(port, '\r'); + + if ( handle & SERHND_HI ) + c |= 0x80; + else if ( handle & SERHND_LO ) + c &= 0x7f; + + __serial_putc(port, c); + } + + spin_unlock_irqrestore(&port->lock, flags); } char serial_getc(int handle) -- 2.30.2